new Vue({
  el: '.container',
  data: {
    forms: [],
    sshs: [],
    formDatas: {},
    formRefs: {}
  },
  created() {
    fetch('/config.json')
    .then(res => res.json())
    .then(config => {
      Object.entries(config).forEach(([key, value]) => {
        if (key === 'env') {
          this.$set(this, 'sshs', value[env].sshs)
        } else {
          this.$set(this, key, value)
        }
      })
      this.forms.forEach((form, i) => {
        if (!form.name) {
          form.name = `form_${i + 1}`
        }

        const name = form.name
        this.$set(this.formDatas, name, {
          project: '',
          module: '',
          build: '',
          filePath: '',
          uploadTo: '',
          ssh: '',
          shell: '',
          ...JSON.parse(localStorage.getItem(env) || '{}')[name]
        })

        const $refs = this.$refs
        this.$set(this.formRefs, name, {
          running: false,
          hasResult: false,
          log: '',
          ctxId: '',
          get value() {
            return $refs[name][0]
          }
        })

        this.$watch(
          `formDatas.${name}`,
          newVal => {
            const data = JSON.parse(localStorage.getItem(env) || '{}')
            data[name] = newVal
            localStorage.setItem(env, JSON.stringify(data))
          },
          { deep: true }
        )
      })
    })

    this.$watch(
      'forms',
      () => {
        this.$nextTick(() => {
          this.$refs.shell.forEach(textarea => {
            this.resize({ target: textarea })
          })
        })
      },
      { deep: true }
    )
  },
  computed: {
    getFormData() {
      return form => this.formDatas[form.name]
    },
    getFormRef() {
      return form => this.formRefs[form.name]
    }
  },
  methods: {
    resize({ target }) {
      target.style.height = 'auto'
      target.style.height = `${target.scrollHeight}px`
    },
    run(formRef, formData) {
      formRef.running = true
      formRef.hasResult = false
      formRef.log = ''
      fetch('/api/deployment/run', {
        method: 'POST',
        headers: {
          'Accept': 'application/json,text/plain',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(formData)
      })
      .then(res => {
        formRef.hasResult = true
        if (!res.ok) {
          formRef.running = false
          res.json().then(json => {
            formRef.log = json
          })
          return
        }

        res.text().then(ctxId => {
          window.addEventListener('unload', () => this.cancel(ctxId))
          formRef.ctxId = ctxId
          const vueInst = this
          const logBuffer = []
          const maxFlushLines = 100
          let flushing = false
          function flushBuffer() {
            if (logBuffer.length === 0) return
            const lines = logBuffer.splice(0, maxFlushLines)
            formRef.log += `${formRef.log && '\n'}${lines.join('\n')}`
            vueInst.$nextTick(() => {
              formRef.value.scrollTop = formRef.value.scrollHeight
            })

            if (logBuffer.length > 0) {
              requestAnimationFrame(flushBuffer)
            }
          }

          const eventSource = new EventSource(`/api/deployment/${ctxId}/log/stream`)
          eventSource.onmessage = event => {
            const line = event.data
            if (!line) return
            if (line === '[DONE]') {
              formRef.running = false
              eventSource.close()
              return
            }

            logBuffer.push(line)
            if (!flushing) {
              flushing = true
              requestAnimationFrame(() => {
                flushBuffer()
                flushing = false
              })
            }
          }
        })
      })
    },
    cancel(ctxId) {
      fetch(`/api/deployment/${ctxId}/cancel`, {
        method: 'POST',
        keepalive: true
      })
    }
  }
})